home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Marathon Map Viewer / @Source / myDocument.cpp < prev    next >
Text File  |  1995-06-06  |  17KB  |  425 lines

  1. /*-----------------------------------------------------------------
  2.     Copyright ©1994 Steve Israelson
  3.     
  4.     This file contains the code for the "myDocument" class.
  5. -----------------------------------------------------------------*/
  6.  
  7. #include "myDocument.h"
  8. #include "myApplication.h"
  9. #include "commandNumbers.h"
  10. #include "chunkStorage.h"
  11. #include "levelView.h"
  12. #include "levelUtils.h"
  13.  
  14. #include <String_Utils.h>
  15. #include <String.h>
  16.  
  17. /*-----------------------------------------------------------------
  18.     Create a new editor document instance.  If no file is passed
  19.     in then we create a new blank document.  This just initializes
  20.     our instance variables to a known state, puts up a window
  21.     to display the level names in, and then opens the file
  22.     and displays the level names.
  23. -----------------------------------------------------------------*/
  24. myDocument::myDocument(LCommander *inSuper, FSSpec *inFileSpec) : LSingleDoc(inSuper)
  25.     {
  26.     // zero out the header.  setmem?
  27.     for (int x = 0; x < sizeof(mapHeader); ++x)
  28.         ((char*)(&theMapFile.theMapHeader))[x] = 0;
  29.  
  30.     // set up the map file for a new file
  31.     strcpy(theMapFile.theMapHeader.name, "Untitled");
  32.     theMapFile.theMapHeader.numLevels = 0;
  33.     theMapFile.theMapHeader.type = 0;
  34.     theMapFile.theMapHeader.flags = 0;
  35.     theMapFile.theMapHeader.mapSize = 0;
  36.     theMapFile.theLevelInfo = nil;
  37.     theMapFile.theLevelData = nil;
  38.     
  39.     levelWindows = nil;
  40.  
  41.     // create the level list window
  42.     mWindow = LWindow::CreateWindow(1000, this);
  43.     if (mWindow)
  44.         {
  45.         LListBox    *theList = (LListBox*) mWindow->FindPaneByID(10000);
  46.         theList->AddListener(this);
  47.         }
  48.     
  49.     // open the file if it is passed in
  50.     if (inFileSpec == nil) 
  51.         NameNewDoc();                // Set name of untitled window
  52.     else 
  53.         OpenFile(*inFileSpec);        // Display contents of file in window
  54.     }
  55.  
  56. /*-----------------------------------------------------------------
  57.     When we have been disposed of we should close any level windows
  58.     that were opened and dispose of any memory we allocated.
  59.     Also close this document.  It should have been saved by now.
  60. -----------------------------------------------------------------*/
  61. myDocument::~myDocument()
  62.     {
  63.     if (theMapFile.theLevelInfo)
  64.         DisposePtr((Ptr)theMapFile.theLevelInfo);
  65.  
  66.     for (int x = 0; x < theMapFile.theMapHeader.numLevels; ++x)
  67.         {
  68.         if (levelWindows[x])
  69.             {
  70.             delete levelWindows[x];    // close all windows with levels showing in them
  71.             levelWindows[x] = nil;
  72.             }
  73.         if (theMapFile.theLevelData[x])
  74.             {
  75.             if (theMapFile.theLevelData[x]->thePoints) DisposePtr((Ptr)theMapFile.theLevelData[x]->thePoints);
  76.             if (theMapFile.theLevelData[x]->theExtendedPts) DisposePtr((Ptr)theMapFile.theLevelData[x]->theExtendedPts);
  77.             if (theMapFile.theLevelData[x]->theLines) DisposePtr((Ptr)theMapFile.theLevelData[x]->theLines);
  78.             if (theMapFile.theLevelData[x]->theSides) DisposePtr((Ptr)theMapFile.theLevelData[x]->theSides);
  79.             if (theMapFile.theLevelData[x]->thePolys) DisposePtr((Ptr)theMapFile.theLevelData[x]->thePolys);
  80.             if (theMapFile.theLevelData[x]->theLites) DisposePtr((Ptr)theMapFile.theLevelData[x]->theLites);
  81.             if (theMapFile.theLevelData[x]->theObjects) DisposePtr((Ptr)theMapFile.theLevelData[x]->theObjects);
  82.             if (theMapFile.theLevelData[x]->theMissionInfo) DisposePtr((Ptr)theMapFile.theLevelData[x]->theMissionInfo);
  83.             if (theMapFile.theLevelData[x]->thePlatforms) DisposePtr((Ptr)theMapFile.theLevelData[x]->thePlatforms);
  84.             if (theMapFile.theLevelData[x]->theiidxs) DisposePtr((Ptr)theMapFile.theLevelData[x]->theiidxs);
  85.             if (theMapFile.theLevelData[x]->theNOTEs) DisposePtr((Ptr)theMapFile.theLevelData[x]->theNOTEs);
  86.             if (theMapFile.theLevelData[x]->theplacs) DisposePtr((Ptr)theMapFile.theLevelData[x]->theplacs);
  87.             if (theMapFile.theLevelData[x]->levelAuthor) DisposePtr((Ptr)theMapFile.theLevelData[x]->levelAuthor);
  88.             DisposePtr((Ptr)theMapFile.theLevelData[x]);
  89.             }
  90.         }
  91.     if (theMapFile.theLevelData)
  92.         DisposePtr((Ptr)theMapFile.theLevelData);
  93.     if (levelWindows)
  94.         DisposePtr((Ptr)levelWindows);
  95.     }
  96.  
  97. /*-----------------------------------------------------------------
  98.     We do not need to name a document in this case.
  99.     This would be called if we let the user create new blank
  100.     documents, in which case we would name the document, "untitled"
  101. -----------------------------------------------------------------*/
  102. void myDocument::NameNewDoc()
  103.     {
  104.     return;    // our palette always has the name of map file.
  105.     }
  106.  
  107. /*-----------------------------------------------------------------
  108.     Open the map file and read some info out of it.
  109.     We need the names of the levels so we can show them to the user
  110.     in our document window.  This window has a listbox in it
  111.     that we fill with the names of all the levels we find.
  112. -----------------------------------------------------------------*/
  113. void myDocument::OpenFile(FSSpec &inFileSpec)
  114.     {
  115.     Try_ {
  116.         mFile = new LFile(inFileSpec);
  117.         mFile->OpenDataFork(fsRdWrPerm);    // the map data is stored in the data fork
  118.         short fileRefNum = mFile->GetDataForkRefNum();
  119.  
  120.         long     count;
  121.         
  122.         // read in the map header
  123.         count = sizeof(mapHeader);
  124.         ThrowIfOSErr_(FSRead(fileRefNum, &count, &theMapFile.theMapHeader));
  125.  
  126.         // create the level window list
  127.         levelWindows = (LWindow**)NewPtrClear(sizeof(LWindow *) * theMapFile.theMapHeader.numLevels);
  128.  
  129.         // create and read in the level info.  It is stored at the end of the file
  130.         count = sizeof(levelInfo) * theMapFile.theMapHeader.numLevels;
  131.         theMapFile.theLevelInfo = (levelInfo*)NewPtrClear(count);
  132.         SetFPos(fileRefNum, fsFromLEOF, -count);
  133.         ThrowIfOSErr_(FSRead(fileRefNum, &count, theMapFile.theLevelInfo));
  134.  
  135.         // create the level info data
  136.         theMapFile.theLevelData = (levelData**)NewPtrClear(sizeof(levelData*) * theMapFile.theMapHeader.numLevels);
  137.         for (int i = 0; i < theMapFile.theMapHeader.numLevels; ++i)
  138.             {
  139.             theMapFile.theLevelData[i] = (levelData*)NewPtrClear(sizeof(levelData));
  140.             // someone will want to talk to us, so save a pointer to us!
  141.             theMapFile.theLevelData[i]->ownerDocument = (Ptr)this;
  142.             }
  143.         
  144.         // read in the name chunks for each level
  145.         // actually only reads in the mission info at this time
  146.         readNameChunks(fileRefNum);
  147.  
  148.         // when edited the level data itself will be read in
  149.         // fill the level names window with the names of all the levels read in.
  150.         setNameList();
  151.  
  152.         // set the name of the window to the name of the map file
  153.         mWindow->SetDescriptor(inFileSpec.name);
  154.         mIsSpecified = true;
  155.         }
  156.     
  157.     Catch_(inErr) {        // we got an error reading in the file
  158.         delete this;
  159.         Throw_(inErr);
  160.         } EndCatch_
  161.     }
  162.  
  163. /*-----------------------------------------------------------------
  164.     Fills the name list with the names from the levels.
  165.     Just gets a pointer to the listbox and then asks it
  166.     for a ListHandle.  The we use the Mac ListManager to
  167.     fill in the entrys for the names of the levels.
  168.     We delete the old names, so if the user adds or changes a level, then
  169.     we can call this to re-build the level name list.
  170. -----------------------------------------------------------------*/
  171. void myDocument::setNameList(void)
  172.     {
  173.     LListBox    *theList = (LListBox*) mWindow->FindPaneByID(10000);
  174.     ListHandle    theMacList = theList->GetMacListH();
  175.  
  176.     LDoDraw(false, theMacList);            // turn drawing off for speed
  177.     LDelColumn(0, 0, theMacList);        // deletes all columns
  178.     LDelRow(0, 0, theMacList);            // deletes all rows
  179.     LAddColumn(1, 10000, theMacList);    // add one at end
  180.     for (int x = 0; x < theMapFile.theMapHeader.numLevels; ++x)
  181.         {
  182.         Point        theCell = {0,0};
  183.  
  184.         theCell.v = LAddRow(1, 10000, theMacList);
  185.         LSetCell(theMapFile.theLevelData[x]->theMissionInfo[0].levelName, 64, theCell, theMacList);
  186.         }
  187.     LDoDraw(true, theMacList);
  188.     theList->Refresh();            // redraw entire list
  189.     }
  190.  
  191. /*-----------------------------------------------------------------
  192.     Reads in the mission info chunks, so we can get the names 
  193.     of the levels.
  194. -----------------------------------------------------------------*/
  195. void myDocument::readNameChunks(short fileRefNum)
  196.     {
  197.     Ptr        chunkData;
  198.  
  199.     for (int x = 0; x < theMapFile.theMapHeader.numLevels; ++x)
  200.         {
  201.         // actually read the chunk in.
  202.         chunkData = readChunk(fileRefNum, 'Minf', theMapFile.theLevelInfo, x);
  203.         if (chunkData)
  204.             {
  205.             theMapFile.theLevelData[x]->numMinfos = GetPtrSize(chunkData) / sizeof(Minfdata);
  206.             theMapFile.theLevelData[x]->theMissionInfo = (Minfdata*)chunkData;
  207.  
  208.             // this fixes the level name string so it will work with the list manager
  209.             Boolean        clear = false;
  210.             for (short i = 0; i < 64; ++i) // clear remaining parts of string to 0 since the list manager displays the entire string
  211.                 {
  212.                 if (!theMapFile.theLevelData[x]->theMissionInfo[0].levelName[i])
  213.                     clear = true;
  214.                 if (clear)
  215.                     theMapFile.theLevelData[x]->theMissionInfo[0].levelName[i] = 0;
  216.                 }
  217.             }
  218.         }
  219.     }
  220.  
  221. /*-----------------------------------------------------------------
  222.     If you want to save a map file, do it here.  Good luck! Its hard.
  223. -----------------------------------------------------------------*/
  224. void myDocument::DoSave()
  225.     {
  226.     }
  227.  
  228. /*-----------------------------------------------------------------
  229.     Has the user changed the file?  If so Powerplant will ask the
  230.     user if it should be saved.
  231. -----------------------------------------------------------------*/
  232. Boolean myDocument::IsModified()
  233.     {
  234.     return mIsModified;
  235.     }
  236.  
  237. /*-----------------------------------------------------------------
  238.     Called for save as, or when saving a new document.
  239. -----------------------------------------------------------------*/
  240. void myDocument::DoAESave(FSSpec &inFileSpec, OSType inFileType)
  241.     {
  242.     }
  243.  
  244. /*-----------------------------------------------------------------
  245.     When a window we created is closed, this is called.
  246.     We update the window list for the level windows.
  247. -----------------------------------------------------------------*/
  248. Boolean myDocument::AllowSubRemoval(LCommander *inSub)
  249.     {
  250.     // need to loop through the levels array and set the appropriate entry to nil
  251.     if (levelWindows)
  252.         {
  253.         for (int x = 0; x < theMapFile.theMapHeader.numLevels; ++x)
  254.             if (levelWindows[x] == inSub)
  255.                 levelWindows[x] = 0;    // closed a level window
  256.         }
  257.     return LSingleDoc::AllowSubRemoval(inSub);
  258.     }
  259.  
  260. /*-----------------------------------------------------------------
  261.     The user wants to revert changes.  Should re-load the level from disk.
  262. -----------------------------------------------------------------*/
  263. void myDocument::DoRevert()
  264.     {
  265.     }
  266.  
  267. /*-----------------------------------------------------------------
  268. -----------------------------------------------------------------*/
  269. void myDocument::DoPrint()
  270.     {
  271.     }
  272.  
  273. /*-----------------------------------------------------------------
  274.     The user double clicked on a level name, so lets open it in a
  275.     window.  This is when the level actually gets read into ram.
  276. -----------------------------------------------------------------*/
  277. void myDocument::editLevel(short theLevelNum)
  278.     {
  279.     if (theLevelNum >= theMapFile.theMapHeader.numLevels || theMapFile.theLevelData[theLevelNum]->deleteMe)
  280.         {
  281.         SysBeep(1);
  282.         return;
  283.         }
  284.     if (levelWindows[theLevelNum])    // already open.
  285.         {
  286.         levelWindows[theLevelNum]->Select();    // so bring it to the front
  287.         return;
  288.         }
  289.     // need to read in the data for the level
  290.     readLevel(theLevelNum);
  291.  
  292.     // create a window to show the level.  A levelView is created by powerplant
  293.     levelWindows[theLevelNum] = LWindow::CreateWindow(1001, this);
  294.     // could re-position the window here
  295.     levelWindows[theLevelNum]->Show();
  296.  
  297.     // set the name of the window to the name of the level
  298.     CtoPstr((char*)theMapFile.theLevelData[theLevelNum]->theMissionInfo[0].levelName);
  299.     levelWindows[theLevelNum]->SetDescriptor((StringPtr)theMapFile.theLevelData[theLevelNum]->theMissionInfo[0].levelName);
  300.     PtoCstr((StringPtr)theMapFile.theLevelData[theLevelNum]->theMissionInfo[0].levelName);
  301.  
  302.     // need to find the pane and set the level data for it
  303.     levelView    *theLevelView = (levelView*) levelWindows[theLevelNum]->FindPaneByID(10000);
  304.     levelWindows[theLevelNum]->SetLatentSub(theLevelView);
  305.  
  306.     // give the levelView the levelData so it can do its thing
  307.     theLevelView->setLevelData(theMapFile.theLevelData[theLevelNum]);
  308.     }
  309.  
  310. /*-----------------------------------------------------------------
  311.     Read the level into ram. This does not assume any particular
  312.     order of the chunks in the file, as per the specs.
  313. -----------------------------------------------------------------*/
  314. void myDocument::readLevel(short theLevelNum)
  315.     {
  316.     theMapFile.theLevelData[theLevelNum]->theMapHeader = &theMapFile.theMapHeader;
  317.     
  318.     if (mFile && !theMapFile.theLevelData[theLevelNum]->readIn)    // are we reading from a file or creating one?
  319.         {
  320.         short        fileRefNum = mFile->GetDataForkRefNum();
  321.         Ptr            chunkData;
  322.  
  323.         theMapFile.theLevelData[theLevelNum]->readIn = true;
  324.  
  325.         // read in 'PNTS', 'LINS', 'SIDS', 'POLY', 'LITE', 'OBJS' etc.
  326.         chunkData = readChunk(fileRefNum, 'NAME', theMapFile.theLevelInfo, theLevelNum);
  327.         if (chunkData)
  328.             {
  329.             theMapFile.theLevelData[theLevelNum]->numNames = GetPtrSize(chunkData) / sizeof(levelName);
  330.             theMapFile.theLevelData[theLevelNum]->levelAuthor = (levelName*)chunkData;
  331.             }
  332.         chunkData = readChunk(fileRefNum, 'PNTS', theMapFile.theLevelInfo, theLevelNum);
  333.         if (chunkData)
  334.             {
  335.             theMapFile.theLevelData[theLevelNum]->numPoints = GetPtrSize(chunkData) / sizeof(PNTSdata);
  336.             theMapFile.theLevelData[theLevelNum]->thePoints = (PNTSdata*)chunkData;
  337.             }
  338.         chunkData = readChunk(fileRefNum, 'EPNT', theMapFile.theLevelInfo, theLevelNum);
  339.         if (chunkData)
  340.             {
  341.             theMapFile.theLevelData[theLevelNum]->numExtendedPts = GetPtrSize(chunkData) / sizeof(EPNTdata);
  342.             theMapFile.theLevelData[theLevelNum]->theExtendedPts = (EPNTdata*)chunkData;
  343.             }
  344.         chunkData = readChunk(fileRefNum, 'LINS', theMapFile.theLevelInfo, theLevelNum);
  345.         if (chunkData)
  346.             {
  347.             theMapFile.theLevelData[theLevelNum]->numLines = GetPtrSize(chunkData) / sizeof(LINSdata);
  348.             theMapFile.theLevelData[theLevelNum]->theLines = (LINSdata*)chunkData;
  349.             }
  350.         chunkData = readChunk(fileRefNum, 'SIDS', theMapFile.theLevelInfo, theLevelNum);
  351.         if (chunkData)
  352.             {
  353.             theMapFile.theLevelData[theLevelNum]->numSides = GetPtrSize(chunkData) / sizeof(SIDSdata);
  354.             theMapFile.theLevelData[theLevelNum]->theSides = (SIDSdata*)chunkData;
  355.             }
  356.         chunkData = readChunk(fileRefNum, 'POLY', theMapFile.theLevelInfo, theLevelNum);
  357.         if (chunkData)
  358.             {
  359.             theMapFile.theLevelData[theLevelNum]->numPolys = GetPtrSize(chunkData) / sizeof(POLYdata);
  360.             theMapFile.theLevelData[theLevelNum]->thePolys = (POLYdata*)chunkData;
  361.             }
  362.         chunkData = readChunk(fileRefNum, 'LITE', theMapFile.theLevelInfo, theLevelNum);
  363.         if (chunkData)
  364.             {
  365.             theMapFile.theLevelData[theLevelNum]->numLites = GetPtrSize(chunkData) / sizeof(LITEdata);
  366.             theMapFile.theLevelData[theLevelNum]->theLites = (LITEdata*)chunkData;
  367.             }
  368.         chunkData = readChunk(fileRefNum, 'NOTE', theMapFile.theLevelInfo, theLevelNum);
  369.         if (chunkData)
  370.             {
  371.             theMapFile.theLevelData[theLevelNum]->numNOTEs = GetPtrSize(chunkData) / sizeof(NOTEdata);
  372.             theMapFile.theLevelData[theLevelNum]->theNOTEs = (NOTEdata*)chunkData;
  373.             }
  374.         chunkData = readChunk(fileRefNum, 'OBJS', theMapFile.theLevelInfo, theLevelNum);
  375.         if (chunkData)
  376.             {
  377.             theMapFile.theLevelData[theLevelNum]->numObjects = GetPtrSize(chunkData) / sizeof(OBJSdata);
  378.             theMapFile.theLevelData[theLevelNum]->theObjects = (OBJSdata*)chunkData;
  379.             }
  380.         chunkData = readChunk(fileRefNum, 'plac', theMapFile.theLevelInfo, theLevelNum);
  381.         if (chunkData)
  382.             {
  383.             theMapFile.theLevelData[theLevelNum]->numplacs = GetPtrSize(chunkData) / sizeof(placData);
  384.             theMapFile.theLevelData[theLevelNum]->theplacs = (placData*)chunkData;
  385.             }
  386.         chunkData = readChunk(fileRefNum, 'plat', theMapFile.theLevelInfo, theLevelNum);
  387.         if (chunkData)
  388.             {
  389.             theMapFile.theLevelData[theLevelNum]->numPlatforms = GetPtrSize(chunkData) / sizeof(platdata);
  390.             theMapFile.theLevelData[theLevelNum]->thePlatforms = (platdata*)chunkData;
  391.             }
  392.         // bungie says do not use EPNTs
  393.         convertEPNTstoPNTS(theMapFile.theLevelData[theLevelNum]);
  394.         }
  395.     else
  396.         {    // create new blank level here
  397.         }
  398.     }
  399.  
  400. /*-----------------------------------------------------------------
  401.     Handle the user double clicking on the level name.
  402. -----------------------------------------------------------------*/
  403. void myDocument::ListenToMessage(MessageT inMessage, void *ioParam)
  404.     {
  405.     switch (inMessage)
  406.         {
  407.         case 1000:        // a level name was double clicked
  408.             LListBox    *theList = (LListBox*) mWindow->FindPaneByID(10000);
  409.             ListHandle    theMacList = theList->GetMacListH();
  410.             Point        theCell = {0,0};
  411.             if (LGetSelect(true, &theCell, theMacList)) 
  412.                 {
  413.                 if (LGrowZone::GetGrowZone()->MemoryIsLow())    // don't let user get into trouble
  414.                     SysBeep(1);
  415.                 else
  416.                     editLevel(theCell.v);    // actually edit the level
  417.                 }
  418.             break;
  419.         }
  420.     }
  421.  
  422.  
  423.  
  424.  
  425.